package com.xinqi.modules.chat.chat.friend.service.impl;

import com.baomidou.dynamic.datasource.annotation.DS;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.xinqi.common.base.enums.YesNoNumberEnum;
import com.xinqi.common.base.error.CommonErrors;
import com.xinqi.common.base.response.PageInfo;
import com.xinqi.common.base.response.Param;
import com.xinqi.common.base.response.R;
import com.xinqi.common.core.constant.ChatConstants;
import com.xinqi.common.core.utils.MessageUtils;
import com.xinqi.common.core.utils.StringUtils;
import com.xinqi.common.mybatis.utils.Pages;
import com.xinqi.common.mybatis.utils.Queries;
import com.xinqi.modules.chat.chat.friend.convert.ChatFriendApplyConvert;
import com.xinqi.modules.chat.chat.friend.domain.ChatFriendApplyEntity;
import com.xinqi.modules.chat.chat.friend.domain.ChatFriendApplyMessageEntity;
import com.xinqi.modules.chat.chat.friend.domain.ChatFriendEntity;
import com.xinqi.modules.chat.chat.friend.dto.req.ChatFriendApplyAutoDTO;
import com.xinqi.modules.chat.chat.friend.dto.req.ChatFriendApplyCreateDTO;
import com.xinqi.modules.chat.chat.friend.dto.req.ChatFriendApplyFindListQueryDTO;
import com.xinqi.modules.chat.chat.friend.dto.req.ChatFriendApplyQueryDTO;
import com.xinqi.modules.chat.chat.friend.dto.rsp.ChatFriendApplyResultDTO;
import com.xinqi.modules.chat.chat.friend.dto.rsp.FreindApplyResultDTO;
import com.xinqi.modules.chat.chat.friend.manager.ChatFriendApplyManager;
import com.xinqi.modules.chat.chat.friend.manager.ChatFriendApplyMessageManager;
import com.xinqi.modules.chat.chat.friend.manager.ChatFriendManager;
import com.xinqi.modules.chat.chat.friend.service.ChatFriendApplyService;
import com.xinqi.modules.chat.chat.message.manager.ChatMessageCountManager;
import com.xinqi.modules.chat.enums.apply.FriendApplyComnonEnum;
import com.xinqi.modules.chat.enums.apply.FriendApplyIsReadEnum;
import com.xinqi.modules.chat.enums.apply.FriendApplyStatusEnum;
import com.xinqi.modules.chat.enums.friend.FriendStatusEnum;
import com.xinqi.modules.chat.favorite.controller.web.utils.LocalDateTimeUtils;
import com.xinqi.modules.user.user.client.UserClient;
import com.xinqi.modules.user.user.dto.req.PhoneLinkerParamDTO;
import com.xinqi.modules.user.user.dto.req.SearchFriendDTO;
import com.xinqi.modules.user.user.dto.rsp.SearchFriendResultDTO;
import lombok.RequiredArgsConstructor;
import lombok.extern.log4j.Log4j2;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.Optional;

/**
 * 加好友申请列表服务层实现
 *
 * @author: system
 * @date: 2023/01/12
 */
@Service("chatFriendApplyService")
@RequiredArgsConstructor
@Log4j2
public class ChatFriendApplyServiceImpl implements ChatFriendApplyService {
    private final ChatFriendApplyConvert chatFriendApplyConvert;
    private final ChatFriendApplyManager chatFriendApplyManager;

    private final ChatFriendManager chatFriendManager;

    private final ChatFriendApplyMessageManager chatFriendApplyMessageManager;

    private final ChatMessageCountManager chatMessageCountManager;

    private final UserClient userClient;

    private final ChatFriendMQService chatFriendMQService;

    private final ChatFriendMessageService chatFriendMessageService;

    /**
     * 好友申请-详情
     *
     * @param id
     * @param operationUserId
     * @return
     */
    @Override
    public ChatFriendApplyResultDTO findById(Long id, Long operationUserId) {
        return chatFriendApplyManager.findById(id, operationUserId);
    }

    /**
     * 申请添加好友
     *
     * @param dto
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long insert(ChatFriendApplyCreateDTO dto) {
        //校验是否是好友
        ChatFriendEntity friend = chatFriendManager.friedByUserIdFriendId(dto.getOperationUserId(), dto.getReceverId());
        //存在
        if (Objects.nonNull(friend)) {
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), friend.getIsFriend())) {
                CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("chat.friend.apply.is.friend"));
            }
        }
        LambdaQueryWrapper<ChatFriendApplyEntity> wrapper = Queries.lambda();
        wrapper.eq(ChatFriendApplyEntity::getStatus, FriendApplyStatusEnum.ZERO.getCode())
            .and(w1 -> (w1.eq(ChatFriendApplyEntity::getApplyerId, dto.getOperationUserId())
                .eq(ChatFriendApplyEntity::getReceverId, dto.getReceverId())
            ).or(w3 ->
                w3.eq(ChatFriendApplyEntity::getApplyerId, dto.getReceverId())
                    .eq(ChatFriendApplyEntity::getReceverId, dto.getOperationUserId())
            ));
        List<ChatFriendApplyEntity> list = chatFriendApplyManager.list(wrapper);
        list.stream().forEach(item -> {
            if (Objects.equals(dto.getOperationUserId(), item.getApplyerId())) {
                CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("chat.friend.apply.is.existence"));
            }
            //校验对方是否给自己发起的申请,保留最新的申请记录
            if (Objects.equals(dto.getOperationUserId(), item.getReceverId())) {
                deleteByApplyId(item.getId());
            }
        });

        ChatFriendApplyEntity entity = chatFriendApplyConvert.create(dto);
        entity.setStatus(FriendApplyStatusEnum.ZERO.getCode());
        entity.setIsRead(FriendApplyIsReadEnum.ZERO.getCode());
        entity.setApplyerId(dto.getOperationUserId());

        boolean flag = chatFriendApplyManager.save(entity);
        if (flag) {
            saveFriendApplyMessage(entity.getId(), dto);
            chatFriendMessageService.sendApplyMsg(entity);
        }
        return entity.getId();
    }

    /**
     * 好友申请列表 -- 分页
     *
     * @param pageable
     * @param query
     * @return
     */
    @Override
    @DS("slaver")
    public PageInfo<ChatFriendApplyResultDTO> findPage(Param pageable, ChatFriendApplyQueryDTO query) {
        return Pages.convert(chatFriendApplyManager.findPage(Pages.page(pageable), query));
    }

    /**
     * 好友申请列表
     *
     * @param query
     * @return
     */
    @DS("slaver")
    @Override
    public FreindApplyResultDTO selectList(ChatFriendApplyFindListQueryDTO query) {
        //获取当天申请记录
        query.setStartTime(LocalDateTimeUtils.getDayStart());
        query.setEndTime(LocalDateTimeUtils.getDayEnd());
        List<ChatFriendApplyResultDTO> toDayList = chatFriendApplyManager.findList(query);
        //获取3天内申请记录
        query.setStartTime(LocalDateTimeUtils.getLocalDateTime(-3L));
        query.setEndTime(LocalDateTimeUtils.getDayStart());
        List<ChatFriendApplyResultDTO> beforelist = chatFriendApplyManager.findList(query);
        //获取3天前申请记录
        query.setEndTime(LocalDateTimeUtils.getLocalDateTime(-3L));
        query.setStartTime(null);
        List<ChatFriendApplyResultDTO> laterlist = chatFriendApplyManager.findList(query);

        FreindApplyResultDTO resultDTO = new FreindApplyResultDTO();
        resultDTO.setToDayList(toDayList);
        resultDTO.setBeforelist(beforelist);
        resultDTO.setLaterlist(laterlist);
        return resultDTO;
    }


    /**
     * 好友申请同意/拒绝
     *
     * @param dto 同意拒绝
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean autoFriend(ChatFriendApplyAutoDTO dto) {
        ChatFriendApplyEntity apply = Optional.ofNullable(chatFriendApplyManager.getById(dto.getId()))
            .orElseThrow(() -> CommonErrors.BAD_REQUEST.asException(MessageUtils.message("data.does.not.exist")));

        CommonErrors.BAD_REQUEST.check(Objects.equals(FriendApplyStatusEnum.ZERO.getCode(), apply.getStatus())
            , MessageUtils.message("chat.friend.apply.is.processed"));
        //被接收方才能操作
        CommonErrors.BAD_REQUEST.check(Objects.equals(dto.getOperationUserId(), apply.getReceverId())
            , MessageUtils.message("chat.friend.apply.permissions.insufficient"));

        apply.setStatus(dto.getStatus().getCode());
        addChatFriend(apply, dto.getRenames());

        ChatFriendApplyEntity autoApply = new ChatFriendApplyEntity();
        autoApply.setId(apply.getId());
        autoApply.setStatus(dto.getStatus().getCode());
        return chatFriendApplyManager.updateById(autoApply);
    }

    /**
     * 好友申请未读，提醒
     *
     * @param userId 当前登录用户
     * @return
     */
    @Override
    @DS("slaver")
    public Integer applyFriendOnRead(Long userId) {
        LambdaUpdateWrapper<ChatFriendApplyEntity> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(ChatFriendApplyEntity::getReceverId, userId)
            .eq(ChatFriendApplyEntity::getIsRead, FriendApplyIsReadEnum.ZERO.getCode());
        return (int) chatFriendApplyManager.count(wrapper);
    }

    /**
     * 当前用户未读清除
     *
     * @param userId 当前登录用户
     * @return
     */
    @Override
    public Boolean applyFriendOnReadClean(Long userId) {
        LambdaUpdateWrapper<ChatFriendApplyEntity> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(ChatFriendApplyEntity::getIsRead, FriendApplyIsReadEnum.ONE.getCode())
            .eq(ChatFriendApplyEntity::getReceverId, userId)
            .eq(ChatFriendApplyEntity::getIsRead, FriendApplyIsReadEnum.ZERO.getCode());
        return chatFriendApplyManager.update(wrapper);
    }

    /**
     * 好友申请过期处理：好友申请过期时间为7天，7天后为处理的申请记录自动变更为过期
     */
    @Override
    public void applyFriendTimeService() {
        //获取七天前的时间，在七天前发起的申请自动过期处理
        LocalDateTime time = LocalDateTime.now().minusDays(7);
        LambdaUpdateWrapper<ChatFriendApplyEntity> wrapper = new LambdaUpdateWrapper<>();
        wrapper.set(ChatFriendApplyEntity::getStatus, FriendApplyStatusEnum.THREE.getCode())
            .eq(ChatFriendApplyEntity::getStatus, FriendApplyStatusEnum.ZERO.getCode())
            .le(ChatFriendApplyEntity::getCreateTime, time);
        chatFriendApplyManager.update(wrapper);
    }

    /**
     * 搜索好友
     *
     * @param dto
     * @return
     */
    @DS("slaver")
    @Override
    public List<SearchFriendResultDTO> selectUsersByKeyword(SearchFriendDTO dto) {
        return R.as(this.userClient.search(dto));
    }

    /**
     * 校验好友
     *
     * @param userId
     * @param operationUserId
     * @return
     */
    @DS("slaver")
    @Override
    public Boolean friedCheck(Long userId, Long operationUserId) {
        LambdaQueryWrapper<ChatFriendEntity> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(ChatFriendEntity::getUserId, operationUserId)
            .eq(ChatFriendEntity::getFriendId, userId)
            .eq(ChatFriendEntity::getIsFriend, YesNoNumberEnum.YES.getCode())
            .last("LIMIT 1");
        return Objects.nonNull(chatFriendManager.getOne(queryWrapper));
    }

    /**
     * 可能认识的人
     *
     * @param operationUserId
     * @return
     */
    @DS("slaver")
    @Override
    public List<SearchFriendResultDTO> myPotential(Long operationUserId) {
        return chatFriendApplyManager.myPotential(operationUserId);
    }

    /**
     * 手机联系人
     *
     * @param dto
     * @return
     */
    @DS("slaver")
    @Override
    public List<SearchFriendResultDTO> phoneLinkerList(PhoneLinkerParamDTO dto) {
        return chatFriendApplyManager.phoneLinkerList(dto);
    }

    /**
     * 根据申请记录ID删除
     *
     * @param applyId
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean deleteByApplyId(Long applyId) {
        chatFriendApplyMessageManager.deleteByApplyId(applyId);
        return chatFriendApplyManager.deleteById(applyId);
    }

    /**
     * 好友申请会话
     *
     * @param applyId 申请记录Id
     * @param dto     ChatFriendApplyCreateDTO
     */
    private void saveFriendApplyMessage(Long applyId, ChatFriendApplyCreateDTO dto) {
        ChatFriendApplyMessageEntity messageEntity = new ChatFriendApplyMessageEntity();
        messageEntity.setUserId(dto.getOperationUserId());
        messageEntity.setApplyId(applyId);
        messageEntity.setContent(dto.getContent());
        chatFriendApplyMessageManager.save(messageEntity);
    }

    /**
     * 双方互加好友
     *
     * @param apply
     * @param renames
     * @return
     */
    private void addChatFriend(ChatFriendApplyEntity apply, String renames) {
        if (!Objects.equals(FriendApplyStatusEnum.ONE.getCode(), apply.getStatus())) {
            return;
        }
        //接收人 - 好友上限1000人
        Long friendCount = chatFriendManager.selectCountFriend(apply.getReceverId());
        if (Objects.nonNull(friendCount) && friendCount >= ChatConstants.CHAT_FRIEND_LIMIT) {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("chat.friend.apply.up.to.valid"));
        }
        //申请人 - 好友上限1000人
        Long userCount = chatFriendManager.selectCountFriend(apply.getApplyerId());
        if (Objects.nonNull(userCount) && userCount >= ChatConstants.CHAT_FRIEND_LIMIT) {
            CommonErrors.BAD_REQUEST.check(false, MessageUtils.message("chat.friend.apply.other.up.to.valid"));
        }

        //同意后互相都是好友 解除双方陌生人聊天限制
        chatMessageCountManager.deleteById(apply.getReceverId(), apply.getApplyerId());
        chatMessageCountManager.deleteById(apply.getApplyerId(), apply.getReceverId());

        //接收人
        ChatFriendEntity recipient = chatFriendManager.friedByUserIdFriendId(apply.getReceverId(), apply.getApplyerId());
        if (recipient == null) {
            recipient = initChatFriendEntity(apply.getReceverId(), apply.getApplyerId(), apply.getComnon(), renames);
            chatFriendManager.save(recipient);
        } else {
            //移除黑名单
            if (Objects.equals(FriendStatusEnum.TWO.getCode(), recipient.getStatus())) {
                chatFriendMQService.privateBlackRemove(recipient);
            }
            //取消免打扰
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), recipient.getIsDisturb())) {
                chatFriendMQService.privateConversationUnMute(recipient);
            }
            //取消置顶
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), recipient.getIsTop())) {
                chatFriendMQService.privateConversationUnTop(recipient);
            }
            chatFriendManager.update(updateWrapper(apply.getComnon(), renames, recipient.getId()));
        }
        //申请人
        ChatFriendEntity applicant = chatFriendManager.friedByUserIdFriendId(apply.getApplyerId(), apply.getReceverId());
        if (applicant == null) {
            applicant = initChatFriendEntity(apply.getApplyerId(), apply.getReceverId(), apply.getComnon(), apply.getRenames());
            chatFriendManager.save(applicant);
        } else {
            //移除黑名单
            if (Objects.equals(FriendStatusEnum.TWO.getCode(), applicant.getStatus())) {
                chatFriendMQService.privateBlackRemove(applicant);
            }
            //取消免打扰
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), applicant.getIsDisturb())) {
                chatFriendMQService.privateConversationUnMute(applicant);
            }
            //取消置顶
            if (Objects.equals(YesNoNumberEnum.YES.getCode(), applicant.getIsTop())) {
                chatFriendMQService.privateConversationUnTop(applicant);
            }
            chatFriendManager.update(updateWrapper(apply.getComnon(), apply.getRenames(), applicant.getId()));
        }
        chatFriendMessageService.sendAddFriendMsg(apply);
    }

    /**
     * 好友初始化
     *
     * @param userId
     * @param friendId
     * @param common
     * @param renames
     * @return
     */
    private ChatFriendEntity initChatFriendEntity(Long userId, Long friendId, Integer common, String renames) {
        ChatFriendEntity entity = new ChatFriendEntity();
        entity.setUserId(userId);
        entity.setFriendId(friendId);
        entity.setComnon(common);
        entity.setRenames(StringUtils.isEmpty(renames) ? StringUtils.EMPTY : renames);
        entity.setStatus(FriendStatusEnum.ONE.getCode());
        entity.setIsFriend(YesNoNumberEnum.YES.getCode());
        entity.setStarMark(YesNoNumberEnum.NO.getCode());
        entity.setIsTop(YesNoNumberEnum.NO.getCode());
        entity.setIsDisturb(YesNoNumberEnum.NO.getCode());
        entity.setHiddenChat(YesNoNumberEnum.NO.getCode());
        return entity;
    }

    /**
     * 非好友变为好友初始化
     * <p>
     * 删除好友，再次添加好友
     * 此时没有添加备注
     * 防止 删除好友后，再次加好友，备注是原来的备注 问题
     *
     * @param common
     * @param renames
     * @param id
     * @return
     */
    private LambdaUpdateWrapper<ChatFriendEntity> updateWrapper(Integer common, String renames, Long id) {
        LambdaUpdateWrapper<ChatFriendEntity> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.set(ChatFriendEntity::getComnon, Objects.isNull(common) ? FriendApplyComnonEnum.MAY_RECOGNIZE.getCode() : common)
            .set(ChatFriendEntity::getRenames, StringUtils.isEmpty(renames) ? StringUtils.EMPTY : renames)
            .set(ChatFriendEntity::getIsFriend, YesNoNumberEnum.YES.getCode())
            .set(ChatFriendEntity::getStarMark, YesNoNumberEnum.NO.getCode())
            .set(ChatFriendEntity::getHiddenChat, YesNoNumberEnum.NO.getCode())
            .set(ChatFriendEntity::getStatus, FriendStatusEnum.ONE.getCode())
            .set(ChatFriendEntity::getIsDisturb, YesNoNumberEnum.NO.getCode())
            .set(ChatFriendEntity::getIsTop, YesNoNumberEnum.NO.getCode())
            .set(ChatFriendEntity::getTopTime, null)
            .eq(ChatFriendEntity::getId, id);
        return updateWrapper;
    }


}
